home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / Apps / EmacsTeX / aa_m68k_Intel_Only / TeXmenu4.1 / Src / slog / slog.m < prev    next >
Encoding:
Text File  |  1995-06-12  |  9.3 KB  |  369 lines

  1. /* Replacement for StuartLog in Stuart2.4.
  2.  *
  3.  * This program is in the public domain.  Use and abuse it as you see fit.
  4.  *
  5.  * This program requires setuid-root to run correctly.  There's
  6.  * now a Makefile that sets all of that up - so use make to compile
  7.  * this.  There will be warnings under NeXSTEP3.0.  Of course,
  8.  * consult Stuart's online documentation under Installation/slot
  9.  * for more information.
  10.  *
  11.  *
  12.  * The StuartLog tool in Stuart2.3 was a good idea, but it didn't
  13.  * quite work.  I found that it would often simply hang during the
  14.  * login process, thus either hanging Stuart or not getting the
  15.  * logging functions done.  slog takes a new approach.  It runs
  16.  * continuously from the time Stuart is launched, and the same process
  17.  * handles all logging functions.  Stuart communicates with slog
  18.  * via a private Speaker/Listener pair.  slog also monitors the
  19.  * parent Stuart process and exits on abnormal termination.
  20.  *
  21.  * Admire the code to connect to the parent process.  I think it
  22.  * cost me a kidney.
  23.  *
  24.  * scott hess
  25.  * shess@ssesco.com
  26.  */
  27. #import "SLogListener.h"
  28. #import <objc/HashTable.h>
  29. #import <libc.h>
  30. #import <grp.h>
  31. #import <lastlog.h>
  32. #import <utmp.h>
  33. #import <ttyent.h>
  34. #import <pwd.h>
  35. #import <mach.h>
  36. #import <mach_error.h>
  37. #import <dpsclient/dpsclient.h>
  38. #import <sys/notify.h>
  39.  
  40. @interface SLogger : Object
  41. {
  42.     SLogListener *listener;
  43.     HashTable *slots;
  44.     int uid;
  45.     const char *name;
  46.     port_t parentNotify;
  47. }
  48. - run;
  49. @end
  50. /* Locking open and close.  Though flock() is not a good general-purpose
  51.  * file locker due to NFS limitations.  It works well for this case
  52.  * since only the local machine can access the devices.
  53.  */
  54. int lopen( const char *filename, int openFlags)
  55. {
  56.     int fd=open( filename, openFlags);
  57.     if( fd>-1) {
  58.     flock( fd, LOCK_EX);
  59.     }
  60.     return fd;
  61. }
  62. int lclose( int fd)
  63. {
  64.     flock( fd, LOCK_UN);
  65.     return close( fd);
  66. }
  67. /* Fix ownerships and permissions on the named pty line. */
  68. void fixOwnership( const char *pty, int uid, int gid, int mod)
  69. {
  70.     char dev[ 64];
  71.     sprintf( dev, "/dev/%s", pty);
  72.     chown( dev, uid, gid);
  73.     chmod( dev, mod);
  74. }
  75. /* Write an entry to wtmp. */
  76. void writeWtmp( struct utmp *ut)
  77. {
  78.     int f=lopen( "/usr/adm/wtmp", O_WRONLY | O_APPEND);
  79.     if( f>=0) {
  80.     write( f, ut, sizeof( struct utmp));
  81.     lclose( f);
  82.     } else {
  83.     perror( "opening /usr/adm/wtmp");
  84.     }
  85. }
  86. /* Write an entry to utmp. */
  87. void writeUtmp( struct utmp *ut, int slot)
  88. {
  89.     if( slot>-1) {
  90.     int f=lopen( "/etc/utmp", O_WRONLY);
  91.     if( f>=0) {
  92.         lseek( f, slot*sizeof( struct utmp), L_SET);
  93.         write( f, ut, sizeof( struct utmp));
  94.         lclose( f);
  95.     } else {
  96.         perror( "opening /etc/utmp");
  97.     }
  98.     }
  99. }
  100.  
  101. @implementation SLogger
  102. /* Initialize uid to an invalid user id (0 is valid). */
  103. - init
  104. {
  105.     self=[super init];
  106.     if( self) {
  107.     uid=-1;
  108.     }
  109.     return self;
  110. }
  111. /* Find the slot in the /etc/ttys file for the given device.  Cache
  112.  * a mapping from the device name to the slot number for future use.
  113.  */
  114. -(int)getSlot:(const char *)device
  115. {
  116.     if( ![slots isKey:device]) {
  117.     struct ttyent *t;
  118.     int slot;
  119.     
  120.     setttyent();
  121.     for( slot=1; t=getttyent(); slot++) {
  122.         if( !strcmp( device, t->ty_name)) {
  123.         break;
  124.         }
  125.     }
  126.     endttyent();
  127.     if( !t) {
  128.         slot=-1;
  129.     }
  130.     if( !slots) {
  131.         slots=[HashTable allocFromZone:[self zone]];
  132.         slots=[slots initKeyDesc:"*" valueDesc:"i" capacity:0];
  133.     }
  134.     device=NXUniqueString( device);
  135.     [slots insertKey:device value:(void *)slot];
  136.     return slot;
  137.     } else {
  138.     return (int)[slots valueForKey:device];
  139.     }
  140. }
  141. /* Login a use on the given pty. */
  142. -(int)login:(char *)pty ownerships:(int)ownership
  143.        utmp:(int)utmp wtmp:(int)wtmp lastlog:(int)lastlog
  144. {
  145.     /* Cache a passwd entry for the user if needed. */
  146.     if( uid==-1) {
  147.     /* Grab a passwd entry, set up uid.  This code was suggested
  148.      * by der Mouse <mouse@larry.mcrcim.mcgill.edu>
  149.      */
  150.     char *user=getenv( "USER");
  151.     struct passwd *pw=NULL;
  152.     uid=getuid();
  153.     if( user) {
  154.         pw=getpwnam( user);
  155.     }
  156.     if( !pw || (uid && (uid!=pw->pw_uid))) {
  157.         pw=getpwuid( uid);
  158.     }
  159.     if( pw) {
  160.         uid=pw->pw_uid;
  161.     }
  162.     if( pw) {
  163.         name=NXUniqueString( pw->pw_name);
  164.     } else {
  165.         name="Unknown";
  166.     }
  167.     }
  168.     if( utmp || wtmp || lastlog) {
  169.     struct utmp ut;
  170.  
  171.     /* Clean up the utmp entry. */
  172.     bzero( &ut, sizeof( ut));
  173.  
  174.     /* Set up the ut_name field if necessary. */
  175.     if( wtmp || utmp) {
  176.         strncpy( ut.ut_name, name, sizeof( ut.ut_name));
  177.     }
  178.  
  179.     /* Setup the line and time. */
  180.     strncpy( ut.ut_line, pty, sizeof( ut.ut_line));
  181.     time( &( ut.ut_time));
  182.  
  183.     /* Log to lastlog as needed. */
  184.     if( lastlog) {
  185.         int f=lopen( "/usr/adm/lastlog", O_WRONLY);
  186.         if( f>=0) {
  187.         struct lastlog llog;
  188.         bzero( &llog, sizeof( llog));
  189.         llog.ll_time=ut.ut_time;
  190.         strncpy( llog.ll_line, ut.ut_line, sizeof( llog.ll_line));
  191.         lseek( f, uid*sizeof( llog), L_SET);
  192.         write( f, &llog, sizeof( llog));
  193.         lclose( f);
  194.         } else {
  195.             perror( "opening /usr/adm/lastlog");
  196.         }
  197.     }
  198.     
  199.     /* Log to utmp and wtmp as needed. */
  200.     if( utmp) {
  201.         writeUtmp( &ut, [self getSlot:pty]);
  202.     }
  203.     if( wtmp) {
  204.         writeWtmp( &ut);
  205.     }
  206.     }
  207.     
  208.     /* If needed, set pty ownership to the new user, with permissions
  209.      * set for owner read/write, group write.  Group ownership set
  210.      * to the tty group, if available.
  211.      */
  212.     if( ownership) {
  213.     struct group *gr=getgrnam( "tty");
  214.     fixOwnership( pty, uid, gr ? gr->gr_gid : -1, 0620);
  215.     }
  216.     return 0;
  217. }
  218. -(int)login:(char *)pty ownerships:(int)ownership utmp:(int)utmp
  219. {
  220. #if 0
  221.     return [self login:pty ownerships:ownership utmp:utmp wtmp:utmp lastlog:utmp];
  222. #else            /* This may make more sense. */
  223.     return [self login:pty ownerships:ownership utmp:utmp wtmp:YES lastlog:YES];
  224. #endif
  225. }
  226. /* This version has the return parameter okFlag which will force
  227.  * Stuart to wait for slog to finish the operation before continuing
  228.  * execution.
  229.  */
  230. -(int)login:(char *)pty ownerships:(int)ownership utmp:(int)utmp ok:(int *)okFlag
  231. {
  232.     return [self login:pty ownerships:ownership utmp:utmp];
  233. }
  234. -(int)logout:(char *)pty ownerships:(int)ownership
  235.     utmp:(int)utmp wtmp:(int)wtmp lastlog:(int)lastlog
  236. {
  237.     if( utmp || wtmp) {
  238.     struct utmp ut;
  239.     
  240.     /* Clean up the utmp entry. */
  241.     bzero( &ut, sizeof( ut));
  242.     
  243.     strncpy( ut.ut_line, pty, sizeof( ut.ut_line));
  244.     time( &( ut.ut_time));
  245.     if( utmp) {
  246.         writeUtmp( &ut, [self getSlot:pty]);
  247.     }
  248.     if( wtmp) {
  249.         writeWtmp( &ut);
  250.     }
  251.     }
  252.  
  253.     /* If needed, set pty ownership back to root user, with permissions
  254.      * set for all read/write.  Group ownership reset to the tty
  255.      * group, if available.
  256.      */
  257.     if( ownership) {
  258.     struct group *gr=getgrnam( "tty");
  259.     fixOwnership( pty, 0, gr ? gr->gr_gid : -1, 0666);
  260.     }
  261.     return 0;
  262. }
  263. -(int)logout:(char *)pty ownerships:(int)ownership utmp:(int)utmp
  264. {
  265. #if 0
  266.     return [self logout:pty ownerships:ownership utmp:utmp wtmp:utmp lastlog:utmp];
  267. #else            /* This may make more sense. */
  268.     return [self logout:pty ownerships:ownership utmp:utmp wtmp:YES lastlog:YES];
  269. #endif
  270. }
  271. /* I use this routine to let Stuart _kindly_ ask slog to exit.  I
  272.  * don't want Stuart doing a kill() on slog while slog's in the middle
  273.  * of something ...
  274.  */
  275. -(void)exit
  276. {
  277.     exit( 0);
  278. }
  279. /* Disconnect our controlling tty and connect to the console device. */
  280. - ttyDisconnect
  281. {
  282.     int tty;
  283.  
  284.     tty=open( "/dev/tty", O_RDWR);
  285.     if( tty>-1) {
  286.     ioctl( tty, TIOCNOTTY, 0);
  287.     close( tty);
  288.     }
  289.     tty=open( "/dev/console", O_WRONLY);
  290.     setpgrp( 0, getpid());
  291.     dup2( tty, 1);
  292.     dup2( tty, 2);
  293.     if( tty!=1 && tty!=2) {
  294.     close( tty);
  295.     }
  296.     return self;
  297. }
  298. /* Catch inadvertant parent process death. */
  299. void notifyPortHandler( notification_t *msg, SLogger *self)
  300. {
  301.     if( msg->notify_header.msg_id==NOTIFY_PORT_DELETED) {
  302.     if( msg->notify_port==self->parentNotify) {
  303.         [self exit];
  304.     }
  305.     }
  306. }
  307. - run
  308. {
  309.     kern_return_t ret;
  310.     msg_header_t initMsg;
  311.     extern int getppid( void);
  312.     task_t parentTask;
  313.     port_t notify;
  314.  
  315.     [self ttyDisconnect];
  316.  
  317.     /* Set up objects for our Listening pleasure. */
  318.     listener=[[SLogListener allocFromZone:[self zone]] init];
  319.     [listener setDelegate:self];
  320.     [listener usePrivatePort];
  321.     [listener addPort];
  322.     /* Give us plenty of leeway for when people logout.
  323.      * Actually, even this isn't really that great,
  324.      * but what can you do?
  325.      */
  326.     port_set_backlog( task_self(), [listener listenPort], PORT_BACKLOG_MAX);
  327.  
  328.     /* Find our parent's notify port. */
  329.     ret=task_by_unix_pid( task_self(), getppid(), &parentTask);
  330.     if( ret!=KERN_SUCCESS) {
  331.     printf( "slog: Unable to get parent's task_t.\n");
  332.     exit( 1);
  333.     }
  334.     ret=task_get_notify_port( parentTask, &parentNotify);
  335.     initMsg.msg_remote_port=parentNotify;
  336.     if( ret!=KERN_SUCCESS) {
  337.     printf( "slog: Unable to get parent's notify port.\n");
  338.     exit( 1);
  339.     }
  340.     port_allocate( task_self(), ¬ify);
  341.     task_set_notify_port( task_self(), notify);
  342.     DPSAddPort( notify, (void *)notifyPortHandler, 64, self, 31);
  343.  
  344.     /* Set up the rest of the header. */
  345.     initMsg.msg_simple=TRUE;
  346.     initMsg.msg_size=sizeof( initMsg);
  347.     initMsg.msg_type=MSG_TYPE_NORMAL;
  348.     initMsg.msg_id=0;
  349.     
  350.     /* Including the port which our Listener listens on. */
  351.     initMsg.msg_local_port=[listener listenPort];
  352.  
  353.     /* Send it, and if successful, enter the event loop. */
  354.     ret=msg_send( &initMsg, SEND_TIMEOUT, 30000);
  355.     if( ret==KERN_SUCCESS) {
  356.     [Listener run];
  357.     }
  358.     printf( "slog: Unable to send Listener port to parent.\n");
  359.     exit( 1);
  360.     return self;
  361. }
  362. @end
  363.  
  364. void main( void)
  365. {
  366.     SLogger *logger=[[SLogger alloc] init];
  367.     [logger run];
  368. }
  369.